package com.wxzhou.wangzhuan.util;

import io.vertx.ext.web.RoutingContext;
import jakarta.enterprise.context.ApplicationScoped;
import org.jboss.logging.Logger;

/**
 * IP地址处理工具类
 * 集成Quarkus环境，支持IP转换和获取真实IP
 * <p>
 * 功能特点：
 * 1. IP字符串与整数的相互转换（节省数据库存储空间）
 * 2. 从Quarkus RoutingContext获取客户端真实IP
 * 3. 支持代理、负载均衡器、CDN等环境下的真实IP识别
 * 4. 防止IP伪造和恶意请求
 * <p>
 * 使用场景：
 * - 评论系统记录用户IP
 * - 访问统计和安全分析
 * - IP黑白名单功能
 */
@ApplicationScoped
public class IpUtils {

    private static final Logger LOG = Logger.getLogger(IpUtils.class);

    /**
     * 将IP字符串转换为整数（用于数据库存储）
     * <p>
     * 转换规则：
     * 192.168.1.1 -> 192*256³ + 168*256² + 1*256¹ + 1*256⁰
     * <p>
     * 优点：
     * - 节省数据库存储空间（INT vs VARCHAR(15)）
     * - 支持IP范围查询和排序
     * - 提高查询性能
     *
     * @param ipStr IP字符串，如 "192.168.1.1"
     * @return IP对应的整数值，无效IP返回0
     */
    public static Integer ipToInt(String ipStr) {
        if (ipStr == null || ipStr.trim().isEmpty()) {
            LOG.warn("IP字符串为空, ipStr=" + ipStr);
            return 0;
        }

        try {
            String[] parts = ipStr.trim().split("\\.");
            if (parts.length != 4) {
                LOG.warn("IP格式不正确, ipStr=" + ipStr + ", parts=" + parts.length);
                return 0;
            }

            long result = 0;
            for (int i = 0; i < 4; i++) {
                int part = Integer.parseInt(parts[i]);
                if (part < 0 || part > 255) {
                    LOG.warn("IP段超出范围, ipStr=" + ipStr + ", part=" + part + ", index=" + i);
                    return 0;
                }
                result = result * 256 + part;
            }

            // 转换为有符号整数
            int ipInt = (int) result;
            LOG.debug("IP转换成功, ipStr=" + ipStr + ", ipInt=" + ipInt);
            return ipInt;

        } catch (NumberFormatException e) {
            LOG.warn("IP转换失败，数字格式错误, ipStr=" + ipStr + ", error=" + e.getMessage());
            return 0;
        } catch (Exception e) {
            LOG.error("IP转换异常, ipStr=" + ipStr, e);
            return 0;
        }
    }

    /**
     * 将整数转换为IP字符串
     * <p>
     * 转换规则：
     * 整数按位拆分为4个字节，每个字节对应IP的一段
     *
     * @param ipInt IP整数值
     * @return IP字符串，如 "192.168.1.1"，无效值返回 "0.0.0.0"
     */
    public static String intToIp(Integer ipInt) {
        if (ipInt == null || ipInt == 0) {
            return "0.0.0.0";
        }

        try {
            // 转换为无符号长整数进行计算，避免负数问题
            long ip = ipInt & 0xFFFFFFFFL;

            int part1 = (int) (ip / (256L * 256L * 256L));
            int part2 = (int) ((ip % (256L * 256L * 256L)) / (256L * 256L));
            int part3 = (int) ((ip % (256L * 256L)) / 256L);
            int part4 = (int) (ip % 256L);

            String ipStr = part1 + "." + part2 + "." + part3 + "." + part4;
            LOG.debug("整数转IP成功, ipInt=" + ipInt + ", ipStr=" + ipStr);
            return ipStr;

        } catch (Exception e) {
            LOG.error("整数转IP异常, ipInt=" + ipInt, e);
            return "0.0.0.0";
        }
    }

    /**
     * 从Quarkus的RoutingContext获取客户端真实IP地址
     * <p>
     * 优先级顺序：
     * 1. X-Forwarded-For（负载均衡器/代理设置）
     * 2. X-Real-IP（Nginx代理设置）
     * 3. CF-Connecting-IP（Cloudflare CDN设置）
     * 4. X-Original-Forwarded-For（其他代理设置）
     * 5. Proxy-Client-IP（Apache代理设置）
     * 6. WL-Proxy-Client-IP（WebLogic代理设置）
     * 7. HTTP_CLIENT_IP（其他客户端IP头）
     * 8. HTTP_X_FORWARDED_FOR（备用转发头）
     * 9. Remote Address（直连地址）
     *
     * @param routingContext Quarkus路由上下文
     * @return 客户端真实IP地址，获取失败返回 "127.0.0.1"
     */
    public static String getRealIpAddress(RoutingContext routingContext) {
        if (routingContext == null || routingContext.request() == null) {
            LOG.warn("RoutingContext为空, context=null");
            return "127.0.0.1";
        }

        try {
            String ip = null;

            // 1. 检查X-Forwarded-For头（最常用，负载均衡器设置）
            ip = routingContext.request().getHeader("X-Forwarded-For");
            if (isValidIp(ip)) {
                // X-Forwarded-For可能包含多个IP，取第一个（真实客户端IP）
                String realIp = ip.split(",")[0].trim();
                if (isValidIp(realIp)) {
                    LOG.debug("从X-Forwarded-For获取IP, ip=" + realIp);
                    return realIp;
                }
            }

            // 2. 检查X-Real-IP头（Nginx代理设置）
            ip = routingContext.request().getHeader("X-Real-IP");
            if (isValidIp(ip)) {
                LOG.debug("从X-Real-IP获取IP, ip=" + ip.trim());
                return ip.trim();
            }

            // 3. 检查CF-Connecting-IP头（Cloudflare CDN设置）
            ip = routingContext.request().getHeader("CF-Connecting-IP");
            if (isValidIp(ip)) {
                LOG.debug("从CF-Connecting-IP获取IP, ip=" + ip.trim());
                return ip.trim();
            }

            // 4. 检查X-Original-Forwarded-For头
            ip = routingContext.request().getHeader("X-Original-Forwarded-For");
            if (isValidIp(ip)) {
                String realIp = ip.split(",")[0].trim();
                if (isValidIp(realIp)) {
                    LOG.debug("从X-Original-Forwarded-For获取IP, ip=" + realIp);
                    return realIp;
                }
            }

            // 5. 检查Proxy-Client-IP头（Apache代理设置）
            ip = routingContext.request().getHeader("Proxy-Client-IP");
            if (isValidIp(ip)) {
                LOG.debug("从Proxy-Client-IP获取IP, ip=" + ip.trim());
                return ip.trim();
            }

            // 6. 检查WL-Proxy-Client-IP头（WebLogic代理设置）
            ip = routingContext.request().getHeader("WL-Proxy-Client-IP");
            if (isValidIp(ip)) {
                LOG.debug("从WL-Proxy-Client-IP获取IP, ip=" + ip.trim());
                return ip.trim();
            }

            // 7. 检查HTTP_CLIENT_IP头
            ip = routingContext.request().getHeader("HTTP_CLIENT_IP");
            if (isValidIp(ip)) {
                LOG.debug("从HTTP_CLIENT_IP获取IP, ip=" + ip.trim());
                return ip.trim();
            }

            // 8. 检查HTTP_X_FORWARDED_FOR头
            ip = routingContext.request().getHeader("HTTP_X_FORWARDED_FOR");
            if (isValidIp(ip)) {
                String realIp = ip.split(",")[0].trim();
                if (isValidIp(realIp)) {
                    LOG.debug("从HTTP_X_FORWARDED_FOR获取IP, ip=" + realIp);
                    return realIp;
                }
            }

            // 9. 使用远程地址（直连情况）
            if (routingContext.request().remoteAddress() != null) {
                ip = routingContext.request().remoteAddress().host();
                if (isValidIp(ip)) {
                    LOG.debug("从RemoteAddress获取IP, ip=" + ip);
                    return ip;
                }
            }

            // 10. 所有方法都失败，返回默认本地IP
            LOG.warn("无法获取真实IP，使用默认值, defaultIp=127.0.0.1");
            return "127.0.0.1";

        } catch (Exception e) {
            LOG.error("获取真实IP异常, fallbackIp=127.0.0.1", e);
            return "127.0.0.1";
        }
    }

    /**
     * 验证IP地址是否有效
     * <p>
     * 验证规则：
     * 1. 不能为空或null
     * 2. 不能是"unknown"等无效标识
     * 3. 不能是本地回环地址
     * 4. 必须符合IPv4格式
     * 5. 每段数字在0-255范围内
     *
     * @param ip IP地址字符串
     * @return 是否为有效的公网IP地址
     */
    private static boolean isValidIp(String ip) {
        if (ip == null || ip.trim().isEmpty()) {
            return false;
        }

        ip = ip.trim();

        // 排除无效IP标识
        if ("unknown".equalsIgnoreCase(ip) ||
                "null".equalsIgnoreCase(ip) ||
                "-".equals(ip)) {
            return false;
        }

        // 排除本地和内网地址（根据业务需求可以调整）
        if ("127.0.0.1".equals(ip) ||
                "localhost".equalsIgnoreCase(ip) ||
                "0:0:0:0:0:0:0:1".equals(ip) ||
                "::1".equals(ip) ||
                "0.0.0.0".equals(ip)) {
            return false;
        }

        // IPv6地址简单排除（暂不支持）
        if (ip.contains(":")) {
            return false;
        }

        // IPv4格式验证
        String[] parts = ip.split("\\.");
        if (parts.length != 4) {
            return false;
        }

        try {
            for (String part : parts) {
                int num = Integer.parseInt(part);
                if (num < 0 || num > 255) {
                    return false;
                }
            }

            // 排除特殊网段（可选，根据业务需求）
            int firstOctet = Integer.parseInt(parts[0]);

            // 排除0.x.x.x网段
            if (firstOctet == 0) {
                return false;
            }

            // 可以根据需要排除内网地址
            // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
            // 如果需要允许内网IP，可以注释掉以下代码
            /*
            if (firstOctet == 10) return false;
            if (firstOctet == 172 && Integer.parseInt(parts[1]) >= 16 && Integer.parseInt(parts[1]) <= 31) return false;
            if (firstOctet == 192 && Integer.parseInt(parts[1]) == 168) return false;
            */

            return true;

        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 判断IP是否为内网地址
     * <p>
     * 内网地址范围：
     * - 10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
     * - 172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
     * - 192.168.0.0/16 (192.168.0.0 - 192.168.255.255)
     * - 127.0.0.0/8 (127.0.0.0 - 127.255.255.255)
     *
     * @param ip IP地址字符串
     * @return 是否为内网地址
     */
    public static boolean isPrivateIp(String ip) {
        if (ip == null || ip.trim().isEmpty()) {
            return false;
        }

        String[] parts = ip.trim().split("\\.");
        if (parts.length != 4) {
            return false;
        }

        try {
            int firstOctet = Integer.parseInt(parts[0]);
            int secondOctet = Integer.parseInt(parts[1]);

            // 127.x.x.x (回环地址)
            if (firstOctet == 127) {
                return true;
            }

            // 10.x.x.x
            if (firstOctet == 10) {
                return true;
            }

            // 172.16.x.x - 172.31.x.x
            if (firstOctet == 172 && secondOctet >= 16 && secondOctet <= 31) {
                return true;
            }

            // 192.168.x.x
            if (firstOctet == 192 && secondOctet == 168) {
                return true;
            }

            return false;

        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 获取IP地址的地理位置描述（占位方法）
     * 后续可以集成第三方IP地理位置服务
     *
     * @param ip IP地址
     * @return 地理位置描述
     */
    public static String getIpLocation(String ip) {
        if (isPrivateIp(ip)) {
            return "内网地址";
        }

        // TODO: 集成第三方IP地理位置服务
        // 如：高德地图API、百度地图API、纯真IP数据库等
        return "未知位置";
    }
}